package com.shadow.study.java.base.util.copy;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;

/**
 * 对象拷贝
 *
 * 浅拷贝：引用类型的成员变量是直接拷贝引用（地址），和原成员变量指向的堆中的同一个对象，优点是速度快，开销小，性能好
 * 深拷贝：引用类型的成员变量是重新创建实例，速度慢，开销大，但更安全，可以避免共用对象导致的问题
 * IO流传输对象时使用的是深拷贝，典型方式是对象的序列化、反序列化，这也是最常见的深拷贝方式
 *
 * spring BeanUtils(浅拷贝)
 * apache BeanUtils(浅拷贝)
 * huTool BeanUtil(浅拷贝)
 * mapStruct(浅拷贝)
 * Cglib的BeanCopier
 * @author shadow
 * */
@Slf4j
public class TestClassCopy {

    private static final String  ID     = "id1";
    private static final String  NAME   = "name";
    private static final String  EXTEND = "extend";
    private static final Integer AGE    = 1;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    static class TestClassCopy1 {

        private String id;
        private String name;
        private Integer age;
        private String extend;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    static class TestClassCopy2 {

        private String id;
        private String name;
        private Integer age;
        private String extend;
    }

    public static void main(String[] args) {
        copyBySpringBeanUtils();
        copyByApacheBeanUtils();
        copyByHuTool();
    }

    /**
     * 简单来说就是将两个字段相同的对象进行属性值的复制
     * source -> target
     * <b>名称不相同的属性 不处理</b>
     * <b>字段区分大小写</b>
     *
     * 将给定源bean的属性值复制到给定的目标bean中，忽略给定的 ignoreProperties
     * 注意：只要属性匹配，源类和目标类不必匹配，甚至不必从彼此派生
     * 源bean公开但目标bean没有公开的任何bean属性都将被忽略。这只是一种方便的方法
     * 对于更复杂的传输需求，可以考虑使用完整的BeanWrapper
     * */
    private static void copyBySpringBeanUtils() {
        TestClassCopy1 testClassCopy1 = new TestClassCopy1(ID, NAME, AGE, EXTEND);
        TestClassCopy2 testClassCopy2 = new TestClassCopy2();
        org.springframework.beans.BeanUtils.copyProperties(testClassCopy1, testClassCopy2);
        log.info(testClassCopy2.toString());
    }

    /**
     * orig (Origin) -> dest (Destination)
     *
     *
     * */
    private static void copyByApacheBeanUtils() {
        TestClassCopy1 testClassCopy1 = new TestClassCopy1(ID, NAME, AGE, EXTEND);
        TestClassCopy2 testClassCopy2 = new TestClassCopy2();
        try {
            org.apache.commons.beanutils.BeanUtils.copyProperties(testClassCopy2, testClassCopy1);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        log.info(testClassCopy2.toString());
    }

    /**
     * source -> tClass
     * ignoreCase -> 是否忽略大小写
     *
     * */
    private static void copyByHuTool() {
        TestClassCopy1 testClassCopy1 = new TestClassCopy1(ID, NAME, AGE, EXTEND);
        TestClassCopy2 testClassCopy2 = cn.hutool.core.bean.BeanUtil.copyProperties(testClassCopy1, TestClassCopy2.class);
        log.info(testClassCopy2.toString());
    }
}
